package com.ygqh.baby.service.impl;

import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.mp.model.User;
import com.foxinmy.weixin4j.tuple.Image;
import com.ygqh.baby.ao.*;
import com.ygqh.baby.constant.RedisConstant;
import com.ygqh.baby.mapper.YgVoteHelpMapper;
import com.ygqh.baby.model.YgVote;
import com.ygqh.baby.model.YgVoteRule;
import com.ygqh.baby.po.*;
import com.ygqh.baby.redis.RedisDao;
import com.ygqh.baby.service.*;
import com.ygqh.baby.utils.DateConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.crazycake.shiro.SerializeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Ss
 */
@Service
public class YgVoteHelpServiceImpl implements YgVoteHelpService {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	private final ExecutorService executorService = Executors.newFixedThreadPool(3);

	@Autowired
	private YgVoteHelpMapper ygVoteHelpMapper;
	@Autowired
	private YgVoteWorkService ygVoteWorkService;
	@Autowired
	private YgUserService ygUserService;
	@Autowired
	private WxMpAuthorityService wxMpAuthorityService;
	@Autowired
	private RedisDao redisDao;
	@Autowired
	private YgCouponDetailService ygCouponDetailService;
	@Autowired
	private YgUserOpenService ygUserOpenService;
	@Autowired
	private YgUserBalanceService ygUserBalanceService;
	@Autowired
	private WxMpMessageService wxMpMessageService;

	@Value("${default.head.url}")
	private String defaultHeadUrl;

	@Override
	public List<YgVoteHelp> find() {
		YgVoteHelpExample example = new YgVoteHelpExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return ygVoteHelpMapper.selectByExample(example);
	}

	@Override
	public int findCount() {
		YgVoteHelpExample example = new YgVoteHelpExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return ygVoteHelpMapper.countByExample(example);
	}

	@Override
	public YgVoteHelp findById(Long id) {
		return ygVoteHelpMapper.selectByPrimaryKey(id);
	}

	@Override
	public int save(YgVoteHelp ygVoteHelp) {
		return ygVoteHelpMapper.insertSelective(ygVoteHelp);
	}

	@Override
	public int update(YgVoteHelp ygVoteHelp) {
		return ygVoteHelpMapper.updateByPrimaryKeySelective(ygVoteHelp);
	}

	@Override
	public int deleteSoft(Long[] ids) {
		Assert.notEmpty(ids);
		YgVoteHelpExample example = new YgVoteHelpExample();
		example.createCriteria().andIdIn(Arrays.asList(ids));
		YgVoteHelp record = new YgVoteHelp();
		record.setStatus(DataStatus.Delete);
		return ygVoteHelpMapper.updateByExampleSelective(record, example);
	}

	@Override
	public int deleteSoft(Long id) {
		return this.deleteSoft(new Long[]{id});
	}

	@Override
	public int saveOrUpdate(YgVoteHelp ygVoteHelp) {
		int r;
		if (ygVoteHelp.getId() != null) {
			r = this.update(ygVoteHelp);
		} else {
			r = this.save(ygVoteHelp);
		}
		return r;
	}

	@Override
	public ResultSet<YgVoteHelp> search(QueryInfo queryInfo, String q) {
		int count = ygVoteHelpMapper.countSuper(q);
		if (count == 0) {
			return new ResultSet<>();
		}
		List<YgVoteHelp> list = ygVoteHelpMapper.selectSuper(queryInfo, q);
		return new ResultSet<>(count, list);
	}

	@Override
	public Message addWxHelp(String seoId, String openId) {
		YgVoteWork voteWork = getVoteWorkFromSeoId(seoId);
		if (voteWork == null) {
			return Message.error("该作品不存在，sourceCode=" + seoId, null);
		}
		YgVote voteInfo = ygVoteWorkService.getVoteInfoFromRedis();
		if (voteInfo == null) {
			return Message.error("活动已结束，sourceCode=" + seoId, null);
		}
		Message validateVoteDateMsg = voteInfo.validateVoteDate();
		if (!Message.isSuccess(validateVoteDateMsg)) {
			return Message.error(validateVoteDateMsg.getContent() + "，sourceCode=" + seoId, null);
		}
		// 校验当前openid是否可投
		Message validateVotableMsg = validateVotable(voteInfo, openId, voteWork);
		if (!Message.isSuccess(validateVotableMsg)) {
			return  Message.success(validateVotableMsg.getContent(), null);
		}
		// 投票
		voteToWork(voteInfo.getVoteBatchCode(), openId, voteWork.getId());
		triggerOtherEvent(openId);

		YgUser user = ygUserService.findByOpenId(openId);
		if (user == null) {
			redisDao.set(String.format(RedisConstant.VOTE_HELP_PREFIX, openId), voteWork.getUserName(), RedisConstant.EXPIRE_OF_DATE);
			return Message.success("投票成功！回复手机号可得60-20优惠券1张。", null);
		}

		if (voteInfo.getCouponCountByGift() != null) {
			int count = ygCouponDetailService.findCount(user.getId(), voteInfo.getCouponIds());
			if (count >= voteInfo.getCouponCountByGift()) {
				return Message.success("投票成功！感谢您参与，加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>", null);
			}
		}
		asyncGiveCouponByHelp(user, voteInfo.getCouponIdByHelpSuccessForOldUser(), "投票成功，sourceCode=" + seoId);
		return Message.success("投票成功！感谢您参与，优惠券已发放至账户，请在“我的-优惠券”查看。\n" +
				"加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>", null);
	}

	@Override
	public String processVoteHelpByStep2(String telPhone, String openId, String fromCode) {
		YgUser user = ygUserService.findByUserName(telPhone);
		if (user != null) {
			return "手机号已存在";
		}
		YgUserOpen userOpen = getUserOpenInfo(openId);
		userOpen.setTelPhone(telPhone);
		userOpen.setFromCode(fromCode);
		YgUser record = this.saveUser(userOpen);
		redisDao.del(String.format(RedisConstant.VOTE_HELP_PREFIX, openId));

		YgVote voteInfo = ygVoteWorkService.getVoteInfoFromRedis();
		if (voteInfo == null) {
			return "投票活动已结束";
		}
		asyncGiveCouponByHelp(record, voteInfo.getCouponIdByHelpSuccessForNewUser(), "投票成功，fromCode=" + fromCode);
		return "优惠券已发放至账户，请在“我的-优惠券”查看。 加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>";
	}

	@SuppressWarnings({"unchecked"})
	private void triggerOtherEvent(String openId) {
		executorService.execute(() -> {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			logger.info("【VoteHelp】投票成功，发送邀请入群通知");
			byte[] bytes = redisDao.get(RedisConstant.YIIGOO_MOTHER_GROUP_QRCODE.getBytes());
			if (bytes == null || bytes.length == 0) {
				return;
			}
			List<String> list = (List<String>) SerializeUtils.deserialize(bytes);
			int index = new Random().nextInt(list.size());
			wxMpMessageService.sendCustomMsg(new Image(list.get(index)), openId, null);
		});
	}

	private YgUser saveUser(YgUserOpen userOpen) {
		YgUser record = new YgUser();
		BeanUtils.copyProperties(userOpen, record);
		record.setUserName(userOpen.getTelPhone());
		record.setPassword("123456a");
		record.setTelPhone(userOpen.getTelPhone());
		record.setSourceCode(userOpen.getTelPhone());
		record.setCreateTime(new Date());
		record.setFromCode(userOpen.getFromCode());
		record.setAppType(AppType.WeChat);
		ygUserService.save(record);

		YgUserBalance userBalance = new YgUserBalance();
		userBalance.setBalancePrice(new BigDecimal(0));
		userBalance.setCreateTime(new Date());
		userBalance.setFreezePrice(new BigDecimal(0));
		userBalance.setPreincomePrice(new BigDecimal(0));
		userBalance.setUserId(record.getId());
		userBalance.setWithdrawPrice(new BigDecimal(0));
		ygUserBalanceService.save(userBalance);

		return record;
	}

	private void asyncGiveCouponByHelp(YgUser user, String couponBatchIds, String remark) {
		if (StringUtils.isNotBlank(couponBatchIds)) {
			executorService.execute(() -> {
				for (String s : couponBatchIds.split(",")) {
					if (StringUtils.isBlank(s)) {
						continue;
					}
					ygCouponDetailService.receiveCouponWithRemark(Long.valueOf(s.trim()), remark, user);
				}
			});
		}
	}

	private void voteToWork(String voteBatchCode, String openId, Long workId) {
		YgVoteHelp voteHelp = this.findLastRecord(voteBatchCode, openId);
		YgVoteHelp record;
		if (voteHelp != null) {
			record = new YgVoteHelp();
			BeanUtils.copyProperties(voteHelp, record);
			record.setId(null);
		} else {
			record = createNewVoteHelpRecord(openId);
			record.setVoteBatchCode(voteBatchCode);
		}
		record.setCreateTime(new Date());
		record.setWorkId(workId);
		int row = this.save(record);
		if (row > 0) {
			ygVoteWorkService.updateVoteCountToUp(workId);
		}
	}

	private YgVoteHelp createNewVoteHelpRecord(String openId) {
		YgUserOpen userOpen = getUserOpenInfo(openId);
		YgVoteHelp record = new YgVoteHelp();
		record.setOpenId(openId);
		record.setHeadImageUrl(userOpen.getHeadImageUrl());
		record.setNickName(userOpen.getNickName());
		return record;
	}

	private YgUserOpen getUserOpenInfo(String openId) {
		YgUserOpen userOpen = ygUserOpenService.findByOpenId(openId);
		if (userOpen == null) {
			userOpen = new YgUserOpen();
			try {
				User wxUser = wxMpAuthorityService.getUserInfo(openId);
				userOpen.setOpenId(openId);
				userOpen.setNickName(wxUser.getNickName());
				String invalideUrl = "/0";
				if (invalideUrl.equals(wxUser.getHeadimgurl())) {
					userOpen.setHeadImageUrl(defaultHeadUrl);
				} else {
					userOpen.setHeadImageUrl(wxUser.getHeadimgurl());
				}
			} catch (WeixinException e) {
				userOpen.setNickName("壹果" + openId.substring(0, 4));
				userOpen.setHeadImageUrl(defaultHeadUrl);
				userOpen.setPassword("123456a");
				logger.error("获取微信用户信息失败; " + e.getMessage(), e);
			}
		}
		return userOpen;
	}

	private YgVoteHelp findLastRecord(String voteBatchCode, String openId) {
		return ygVoteHelpMapper.selectLast(voteBatchCode, openId);
	}

	private Message validateVotable(YgVote voteInfo, String openId, YgVoteWork voteWork) {
		String voteBatchCode = voteInfo.getVoteBatchCode();
		YgVoteRule voteRole = voteInfo.getVoteRule();
		if (voteRole == null) {
			return Message.success(null);
		}
		if (voteRole.getTotalCount() != null) {
			int totalCount = this.findCount(voteBatchCode, openId);
			if (totalCount >= voteRole.getTotalCount()) {
				return Message.error("每人只能投" + voteRole.getTotalCount() + "票哦，下次活动再来吧~\n" +
						"加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>", null);
			}
		}
		if (voteRole.getCountPerDay() != null) {
			int countPerDay = this.findCount(voteBatchCode, openId, DateConvertUtils.getDateStart(new Date()));
			if (countPerDay >= voteRole.getCountPerDay()) {
				return Message.error("每天只能投" + voteRole.getCountPerDay() + "票哦，明天再来吧~\n" +
						"加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>", null);
			}
		}
		if (voteRole.getCountPerPerson() != null) {
			int countPerPerson = this.findCount(voteBatchCode, openId, voteWork.getId());
			if (countPerPerson >= voteRole.getCountPerPerson()) {
				return Message.error("每人对同一个作品只能投" + voteRole.getCountPerPerson() + "票哦，下次活动再来吧~\n" +
						"加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>", null);
			}
		}
		if (voteRole.getCountPerDayAndPerson() != null) {
			int countPerDayAndPerson = this.findCount(voteBatchCode, openId, DateConvertUtils.getDateStart(new Date()), voteWork.getId());
			if (countPerDayAndPerson >= voteRole.getCountPerDayAndPerson()) {
				return Message.error("每天对同一个作品只能投" + voteRole.getCountPerDayAndPerson() + "票哦，明天再来吧~\n" +
						"加入壹果妈妈群，享受群特价、群专属优惠券。入群<a href=\"http://m.yiigoo.com/static/1534417413.html\">点这里</a>", null);
			}
		}
		return Message.success(null);
	}

	private int findCount(String voteBatchCode, String openId) {
		return findCount(voteBatchCode, openId, null, null);
	}

	private int findCount(String voteBatchCode, String openId, Date specifiedTime) {
		return findCount(voteBatchCode, openId, specifiedTime, null);
	}

	private int findCount(String voteBatchCode, String openId, Long workId) {
		return findCount(voteBatchCode, openId, null, workId);
	}

	private int findCount(String voteBatchCode, String openId, Date specifiedTime, Long workId) {
		Assert.isTrue(StringUtils.isNotBlank(openId), "Param 'voteBatchCode' must not be blank");
		Assert.isTrue(StringUtils.isNotBlank(openId), "Param 'openId' must not be blank");
		YgVoteHelpExample exmaple = new YgVoteHelpExample();
		YgVoteHelpExample.Criteria criteria = exmaple.createCriteria().andVoteBatchCodeEqualTo(voteBatchCode).andOpenIdEqualTo(openId);
		if (specifiedTime != null) {
			criteria.andCreateTimeGreaterThanOrEqualTo(DateConvertUtils.getDateStart(new Date()));
		}
		if (workId != null) {
			criteria.andWorkIdEqualTo(workId);
		}
		criteria.andStatusEqualTo(DataStatus.Valid.name());
		return ygVoteHelpMapper.countByExample(exmaple);
	}

	private YgVoteWork getVoteWorkFromSeoId(String seoId) {
		try {
			String[] split = seoId.split("-");
			return ygVoteWorkService.findById(Long.valueOf(split[1]));
		} catch (NumberFormatException e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

}

